package com.smark.sbrabbitmqfanoutproducer.order;

import com.rabbitmq.client.Channel;
import com.smark.sbrabbitmqfanoutproducer.dead.RabbitDeadLetterConfig;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

/**
 * @author smark
 */
@Component
//1、会把申请的队列和交换机进行绑定
// 2、确定消息的模式 fanout direct topic
// 3、确定消息queue的持久性
@RabbitListener(bindings =@QueueBinding(value = @Queue(value = "${order.direct.email.queue}",autoDelete = "false"), exchange = @Exchange(value =
        "${mq.config.exchange}",type = ExchangeTypes.DIRECT),key = "order"
))
public class OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RabbitHandler
    public void receiveMessages(String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag, Message message){
        //目的：在网络出现问题的情况下，达到数据一致性
        //1、可靠消费
        //正常情况下，消费者正常，就直接告诉rabbitmq服务去收到消息，就自动确认，并且将消息删除掉
        //异常情况下：消费者异常，rabbitmq服务一直收不到自动确认，就会启用rabbitmq的basicNack重试机制，出现死循环
        //解决方法
        // 1、try/catch 自己处理（利用消息转移+消息重试+死信队列+重定向队列+人工干预+预警）
        // 2、开启 错的重试次数，如果达到重试次数直接扔掉（不建议使用，会造成消息丢失）

        //2、可靠生产（分布式事务） rabbitmq不需要回滚的分布式事务
        // 分布式事务：不回滚（rabbitmq/activemq/tcc） 回滚：（2pc/3pc/异步校对/atomicok）
        //ack手动+reture/confim机制
        // 消息冗余 、定时任务重发（3/5）
        try {
            System.out.println("order------------"+msg);
            System.out.println(1/0);
        }catch (Exception ex){
            Boolean redelieved = message.getMessageProperties().getRedelivered();
            System.out.println("======>"+redelieved);
            try {
                if(redelieved){
                    channel.basicReject(tag,false);
                    System.out.println("消息【"+msg+"]重新处理失败，扔掉消息");
                    //消息转移，死信队列
                    rabbitTemplate.convertAndSend(RabbitDeadLetterConfig.DEAD_LETTER_EXCHANGE,
                            RabbitDeadLetterConfig.DEAD_LETTER_TEST_ROUTING_KEY,msg);
                }
                if(!redelieved){
                    channel.basicNack(tag,false,true);
                    System.out.println("消息【"+msg+"]重新处理失败，扔掉消息");
                }
            }catch (Exception e){

            }
        }

    }

}
